// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace SnapObjects.Data
{
    internal class LazyQueryable<TModel> : ILazyQueryable<TModel>
    {
        private readonly IAdoDbConnection _connection;
        private readonly IAdoDbResultSet<TModel> _resultSet;
        private bool _disposed = false;

        public LazyQueryable(
            IAdoDbConnection connection, IAdoDbResultSet<TModel> resultSet)
        {
            _connection = connection;

            _resultSet = resultSet;
        }

        public TModel Current => ((AdoDbResultSet<TModel>)_resultSet).Current;

        ~LazyQueryable()
        {
            this.Dispose();
        }

        object IEnumerator.Current => this.Current;

        public IEnumerator<TModel> GetEnumerator()
        {
            return this;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        public bool MoveNext()
        {
            return _resultSet.MoveNext();
        }

        public void Reset()
        {
            _resultSet.Reset();
        }

        public void Dispose()
        {
            if (!_disposed)
            {
                _resultSet.Dispose();

                _connection.Close();

                _disposed = true;
            }
        }

        public IAsyncEnumerator<TModel> GetAsyncEnumerator(CancellationToken cancellationToken = default)
        {
            return _resultSet.GetAsyncEnumerator(cancellationToken);
        }

        public ValueTask<bool> MoveNextAsync()
        {
            return _resultSet.MoveNextAsync();
        }

        public async ValueTask DisposeAsync()
        {
            if (!_disposed)
            {
                await _resultSet.DisposeAsync();

                await _connection.CloseAsync();

                _disposed = true;
            }
        }
    }
}
